perm filename OC.FIX[MF,ALS] blob
sn#764503 filedate 1984-08-03 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00005 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00002 00002 @* OC Matrix Format.
C00010 00003 IFDOVERMODES
C00014 00004 Since the details of the header information cannot be known until much of
C00019 00005 internal procedure charclear # initializes parameters for a new character
C00033 ENDMK
C⊗;
@* OC Matrix Format.
A \.{OC} file is an expanded raster description of a single font at a
particular resolution and contains essentially the same information as
that contained in a \.{GF} file. \.{OC} files are used by the Dover.
All words in of \.{OC} files are in 32-bit format, with the four lower
bits zero on 36-bit machines.
By convention, \.{OC} files
are for 384 pixels per inch. \.{GFtoOC} will report the magnification
over the design point size that will occur if the \.{OC} file is
used on a 384 pixel per inch output device. Fonts specifically designed
for the Dover will report a magnification of 1000.
Data segments of type OrbitChars have an internal structure that is a
minature version of the structure of the complete dictionary file. At the
beginning of these segements, there is a table of header information that
specifies the dimensions and widths of each character in the font. Next
there is a table of file pointers that give, for each character code, the
location of the corresponding raster block. And finally, there are the
raster blocks themselves.
The raster information is contained in a sequence of binary words that
record white pixels as zeros and black pixels as ones. Furthermore, this
raster information is written in a rotated form, as compared with the
convention for \.{PXL} files, reporting the pixels as read from the bottom
left corner of the glyph, reading up the leftmost column, with this being
followed imediately by the next column, again from bottom to top, without
any unused bit locations between columns. The final half word is, however
padded out with zeros.
We will need the following arrays to accumulate information regarding all
of the glyphs as they ae beng processed:
@d char_seg_file_pos='3000 {earliest |file_pos| of individual char segments}
@d no_char_flag=-(2.0↑120) {real that won''t otherwise appear as |char_width_x|}
@ @<Glob...@>=
@!glyph_ptr: array [0..max_glyph_no] of integer; {called charsegfilepos in mf.old}
@!glyph_cols: array [0..max_glyph_no] of integer;
@!glyph_rows: array [0..max_glyph_no] of integer;
@!cols_offset: array [0..max_glyph_no] of integer;
@!rows_offset: array [0..max_glyph_no] of integer;
@!bc,ec:integer;
@!oc_dir_ptr:integer;
@!oc_mag: integer;
IFDOVERMODES
'20000000 make Dover .OC font
'40000000 make PrePress-style widths (.WD) file
'100000000 use charwx and charwy to get vector style widths
ENDDOVERMODES;
IFDOVERMODES
define ocmode=⊂(control land '20000000)⊃, wdmode=⊂(control land '40000000)⊃;
define vectorwidths=⊂(control land '100000000)⊃;
ENDDOVERMODES
IFDOVERMODES
internaldef numberofmodes=8;
internaldef doveroc=7,presswd=8;
ENDDOVERMODES
IFDOVERMODES
define nonexistentcharflag=⊂-(2.0↑120)⊃ # a real number that won't occur
as the vector width X component of any real character;
saf real array CharWidthX[0:'177];
saf real array CharWidthY[0:'177] # x and y components of
the vector widths of characters;
integer bbxlmin, bbxrmax, bbylmin, bbyhmax # extremes of bounding box;
real charwxmax, charwxmin, charwymax, charwymin # extremes of width vector
components;
define IX(typ, lngth)=⊂((typ lsh 12)+lngth)⊃;
saf integer array charsegptr[0:'177] # filepos's of individual char segments;
define charsegfilepos=⊂('3000)⊃ # earliest filepos in .oc file that a
character segment can start (in 16-bit words), rounded up to the
nearest multiple of 2*pagesize(For WAITS' sake!);
ENDDOVERMODES
IFDOVERMODES
[presswd] begin
arrclr(CharWidthX,nonexistentcharflag) # mark all characters as missing;
bbxlmin←infty; bbxrmax←-infty;
bbylmin←infty; bbyhmax←-infty;
charwxmin←infty; charwxmax←-infty;
charwymin←infty; charwymax←-infty;
end;
[doveroc] begin
for i←1 thru charsegfilepos div 2 do wordout(ochan[doveroc],0);
bytecount[doveroc]←charsegfilepos*2 # start of first character segment;
arrclr(charsegptr,-1) # mark all characters as missing;
end;
ENDDOVERMODES
IFDOVERMODES require "MFDOVR.SAI" source_file; ENDDOVERMODES
IFDOVERMODES ofilext[doveroc]←".oc"; ofilext[presswd]←".wd"; ENDDOVERMODES
IFDOVERMODES bndboxvalid←false; ENDDOVERMODES
IFDOVERMODES
if ocmode then makeoc;
if wdmode then makewd;
ENDDOVERMODES
IFDOVERMODES
if ochan[doveroc]≥0 then
begin occloseout;
binaryrelease(ochan[doveroc]);
print(nextline,"Images written on ",flname[doveroc]);
end;
if ochan[presswd]≥0 then
begin wdcloseout;
binaryrelease(ochan[presswd]);
print(nextline,"PrePress-style widths written on ",flname[presswd]);
end;
ENDDOVERMODES
Since the details of the header information cannot be known until much of
the work has been done toward creating the raster information itself, the
\.{OC} format arrangwes for the raster information to start at byte '3000
and we arrange for this, initially, by writing zeros in the first '3000
bytes. We then proceed to write the raster information, one glyph at a
time, and save the necessary header information in global arrays. After
the last glyph has been processed, we then write out the header.
The header consists of a block of 24 half-words that are characteristic of the
font in general followed by a character width table and finally by the
character-segment pointers.
The header consists of a block of 24 half-words that are characteristic of
the font in general followed by a character width table and finally by the
character-segment pointers.
There need not be a complete set of 128 glyphs in the font but it will be
assumed that the set is reasonably complete within a group from a
character number of |bc| through |ec|. There will be a set of 8
half-words of width information for each character within this group (with
a standard notation for all missing glyphs).
There will be a similar set of |ec| $-$ |bc| $+$ 1 pointers, each
occupying two half-words, for the raster information for each character
(with pointers of $-1$ for missing characters).
The initial 24 half-words of the header will contain:
\smallskip\hang\noindent
0. A header for the family-name IX.
\smallskip\hang\noindent
1. The font name code.
\smallskip\hang\noindent
2..11.. A 20-character font identifier string.
\smallskip\hang\noindent
12. Header for orbit-chars IX.
\smallskip\hang\noindent
13. Name code again in left byte and logical size encoded as face byte.
\smallskip\hang\noindent
14. |bc| in left byte and |ec| in right byte.
\smallskip\hang\noindent
15. Physical size in micas (real).
\smallskip\hang\noindent
16. Rotation in minutes of arc.
\smallskip\hang\noindent
17..18. Starting file position of font segment.
\smallskip\hang\noindent
19..20. Font segment length.
\smallskip\hang\noindent
21. X resolution in units of pixels/(10 inchs) (real)
\smallskip\hang\noindent
22. Y resolution in units of pixels/(10 inches) (real).
\smallskip\hang\noindent
23. EndIX.
\smallskip
The 8 words of width information for each |ec|$-$|bc|$+1$ entry will contain:
\smallskip\hang\noindent
0,1. X-width$*$xresolution$*(2↑16)$.
\smallskip\hang\noindent
2,3. Y-width$*$yresolution$*(2↑16)$.
\smallskip\hang\noindent
4. Bounding box x-offset.
\smallskip\hang\noindent
5. Bounding box y-offset.
\smallskip\hang\noindent
6. Bounding box x-width in scan lines.
\smallskip\hang\noindent
7. Bounding box y-height in bits.
\smallskip
Finally the raster information for each glyph will occupy a varying amount
of space up to a limit of
(((|right_pixel|-|left_pixel|)*(|top_pixel|-|bot_pixel|)+15)div 16 half-words,
although most glyphs will not occupy this much space.
internal procedure charclear # initializes parameters for a new character;
begin charwd←chardp←charht←charic←charwx←charwy←0.0; isvarchar←false;
chardw←0; charcode←-1;
brkptr[0]←brkptr[1]←0; brktab[0,0]←brktab[1,0]←1 lsh (bitsperwd-1);
IFDOVERMODES bndboxvalid←false; ENDDOVERMODES
end;
A COMMENT THAT MAY HELP****
comment Routines for chr mode.
In this mode we output the characters in asterisk-dot form. Exactly two
columns have more than one dot, these columns specifying the pixels to the
left and right of the character (columns -1 and chardw).
Exactly one row has more than two dots, this row being the baseline (row 0);
define charwx=⊂realparam[24]⊃ # x component of vector width;
define charwy=⊂realparam[25]⊃ # y component of vector width;
define charwd=⊂realparam[7]⊃ # width of character to be output;
define charht=⊂realparam[8]⊃ # height of character to be output;
define chardp=⊂realparam[9]⊃ # depth of character to be output;
comment Routines for Dover-style .oc files;
comment In this mode, we output characters as Orbitized PARC-style
.AC files with a rotation of 0 minutes. This demands both changing to
32 bitsperword from 36, and also rotating the raster 90 degrees, because
the conventions of .AC format dictate that a non-rotated character is
scanned from bottom-to-top, left-to-right (as Dover's scan);
@ @<Glob...@>=
@!glyph_ptr: array [0..max_glyph_no] of integer;
@!glyph_cols: array [0..max_glyph_no] of integer;
@!glyph_rows: array [0..max_glyph_no] of integer;
@!cols_offset: array [0..max_glyph_no] of integer;
@!rows_offset: array [0..max_glyph_no] of integer;
@!bc,ec:integer;
@!oc_dir_ptr:integer;
@!oc_mag: integer;
saf integer array
BBoxArray,
BBoyArray,
BBdxArray,
BBdyArray[0:'177];
bbxl←xlb; bbxr←xrb; bbyl←yl; bbyh←yh;
bbdx←xrb-xlb+1; bbdy←yh-yl+1; bbox←xlb; bboy←yl;
emptychar←false; bndboxvalid←true;
integer bbox,bboy,bbdx,bbdy,bbxl,bbxr,bbyl,bbyh # dimensions of the
character bounding box, set by bndbox;
boolean emptychar # true iff char has empty raster, set by bndbox;
define bitloc(x)=⊂((x+(1000*bitsperwd+hw-1))mod bitsperwd)⊃ # number of
bits to the left of bit x, copied from mfrast;
boolean bndboxvalid # true iff bndbox has been called for this character;
procedure bndbox;
comment this procedure computes the bounding box of the character in
pixel coordinates, since both .oc and .wd format demand it. Leaves
coordinates of bounding box in bb** global integers---returns
true iff the raster is non-blank;
begin integer i,xw,y,z,xl,xr,lz,lzr,xlb,xrb,yl,yh;
label nonblank3,nonblank4;
xl←xleft; xr←xright; z←0;
loop begin comment try to eliminate blank column at left;
xw←xl*rspan;
for y←xw+ylow thru xw+yhigh do
var!gets!rast!lor!var(z,y) # z←z lor rast[y];
if z then done;
xl←xl+1;
if xl>xr then
begin comment blank raster;
bbdx←bbdy←bbox←bboy←0;
bbxl←0; bbxr←-1; bbyl←0; bbyh←-1 # as good as any other;
emptychar←true; bndboxvalid←true;
return;
end;
end;
lz←0; while z>0 do
begin lz←lz+1; z←z lsh 1;
end;
xlb←(1-hw-bitsperwd*rcol(0))+lz+bitsperwd*xl;
z←0;
loop begin comment try to eliminate blank column at right. The
loop is guaranteed to halt, since raster is non-empty;
xw←xr*rspan;
for y←xw+ylow thru xw+yhigh do
var!gets!rast!lor!var(z,y) # z←z lor rast[y];
if z then done;
xr←xr-1;
end;
comment Assert z≠0;
lzr←rightmostbitindex(z);
xrb←(1-hw-bitsperwd*rcol(0))+lzr+bitsperwd*xr;
yl←ylow; yh←yhigh;
loop begin comment try to eliminate blank row at bottom;
for xw←xl*rspan+yl step rspan until xr*rspan+yl do
IFXMEM begin var!gets!rast(xtemp,xw); if xtemp then go to nonblank3; end;
ELSEC if rast[xw] then go to nonblank3;
ENDC
yl←yl+1;
end;
nonblank3:
loop begin comment try to eliminate blank row at top;
for xw←xl*rspan+yh step rspan until xr*rspan+yh do
IFXMEM begin var!gets!rast(xtemp,xw); if xtemp then go to nonblank4; end;
ELSEC if rast[xw] then go to nonblank4;
ENDC
yh←yh-1;
end;
nonblank4:
bbxl←xlb; bbxr←xrb; bbyl←yl; bbyh←yh;
bbdx←xrb-xlb+1; bbdy←yh-yl+1; bbox←xlb; bboy←yl;
emptychar←false; bndboxvalid←true;
end;
procedure makeoc # outputs the current character to .oc file;
begin integer i,x,y,ch;
integer padbits, charbits, charwords;
integer coladdr, wdaddr, shft, bitptr, pfield, accum, ocfilepos;
ch←openofil(doveroc);
if not bndboxvalid then bndbox;
if charsegptr[charcode]≠-1 then error("Duplicate charcode: '"&cvos(charcode));
BBdxArray[charcode]←bbdx; BBdyArray[charcode]←bbdy;
BBoxArray[charcode]←bbox; BBoyArray[charcode]←bboy;
if not vectorwidths then
begin
charwx←charwd;
charwy←0.0;
end;
CharWidthX[charcode]←charwx;
CharWidthY[charcode]←charwy;
charbits←bbdx*bbdy;
charwords←2*((charbits+31) div 32) # orbitchars block must be
and even number of sixteen-bit words;
padbits←16*charwords-charbits;
charsegptr[charcode]←bytecount[doveroc] div 2 # bytes to 16-bit words;
comment Send the character segment out to the file:;
Wout(doveroc,-bbdy);
Wout(doveroc,bbdx-1);
accum←0; bitptr←point(1,accum,-1);
pfield←point(6,bitptr,5) # points at the "P" field of bitptr;
for x←bbxl thru bbxr do
begin "move one column"
coladdr←rcol(x)*rspan;
shft←(bitloc(x)-35);
for wdaddr←coladdr+bbyl thru coladdr+bbyh do
begin "move one bit"
IFXMEM var!gets!rast!lsh!expr(xtemp,wdaddr,shft); idpb(xtemp,bitptr);
ELSEC idpb(rast[wdaddr] lsh shft,bitptr);
ENDC
if ldb(pfield)=4 then
begin
dpb(36,pfield) # reset bitptr to left end of accum;
DoutAligned(doveroc,accum);
end;
end "move one bit";
end "move one column";
for i←1 thru padbits do idpb(0,bitptr);
if ldb(pfield)=4 then
begin
dpb(36,pfield) # reset bitptr to left end of accum;
DoutAligned(doveroc,accum);
end;
if ldb(pfield)≠36 then confusion;
end;
procedure occloseout;
begin
integer i,c,bc,ec,nc; integer fontsegstart, fontsegend, relptrbase;
integer ch # channel for output;
ch←ochan[doveroc];
for bc←0 step 1 until '177 do if charsegptr[bc]≠-1 then done;
for ec←'177 step -1 until 0 do if charsegptr[ec]≠-1 then done;
if bc>ec then
begin
bc←1; ec←0;
error("No characters in this font");
end;
nc←ec-bc+1;
if fontfacebyte<0 or fontfacebyte>255 then
error("Fontfacebyte out of bounds");
while rotation>360 do rotation←rotation-360;
while rotation<0 do rotation←rotation+360;
fontsegstart←charsegfilepos-(8+2)*nc;
fontsegend←bytecount[doveroc] div 2;
useto(ch,1) # reset file position to beginning;
bytecount[doveroc]←0;
Wout(doveroc,IX(1,12)) # header for family-name IX;
Wout(doveroc,0) # name code;
BCPLout(doveroc,fontidentifier,20);
Wout(doveroc,IX(5,11)) # header for orbit-chars IX;
Bout(doveroc,0) # name code again;
Bout(doveroc,fontfacebyte) # logical size encoded as face byte;
Bout(doveroc,bc); Bout(doveroc,ec);
define ppi=⊂72.27⊃ # points per inch according to TEX/Metafont;
Wout(doveroc,(designsize*magnification*2540/ppi)+0.5) # physical siz in micas;
Wout(doveroc,(60*rotation)+0.5) # rotation in minutes of arc;
Dout(doveroc,fontsegstart) # starting file pos of font segment;
Dout(doveroc,fontsegend-fontsegstart) # and font segment length;
Wout(doveroc,(xresolution*ppi*10/magnification)+0.5) # X resolution in
units of pixels/(10 inches);
Wout(doveroc,(yresolution*ppi*10/magnification)+0.5) # Y resolution in
units of pixels/(10 inches);
Wout(doveroc,IX(0,1)) # endIX;
comment next, write the char width table and char segment ptrs--first
get to the correct place in the file;
DEBUGONLY if bytecount[doveroc]≠2*('30) then confusion;
for i←1 thru (fontsegstart-'30) div 2 do DoutAligned(doveroc,0);
for c←bc thru ec do
if charsegptr[c]≠-1 then
begin
comment Convert the spacing Xwidth of the character
from points into (fixed.fraction) pixels;
integer newwidth;
newwidth←(CharWidthX[c]*xresolution*(2↑16))+0.5;
Dout(doveroc,newwidth);
newwidth←(CharWidthY[c]*yresolution*(2↑16))+0.5;
Dout(doveroc,newwidth);
Wout(doveroc,BBoxArray[c]);
Wout(doveroc,BBoyArray[c]);
Wout(doveroc,BBdxArray[c]);
Wout(doveroc,BBdyArray[c]);
end
else begin
integer i;
for i←1 thru 7 do Wout(doveroc,0);
Wout(doveroc,-1) # marks a non-existent character;
end;
relptrbase←charsegfilepos-2*nc;
DEBUGONLY if bytecount[doveroc]≠relptrbase*2 then confusion;
for c←bc thru ec do
if charsegptr[c]≠-1 then Dout(doveroc,charsegptr[c]-relptrbase)
else Dout(doveroc,-1);
end;